/*
Kakine
ActionScript Framework
Copyright © 2011, PUNY, LLC.

This file is part of KAKINE.

KAKINE is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

KAKINE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with KAKINE.  If not, see <http://www.gnu.org/licenses/>.
*/ 
package com.puny.utils
{
	import com.puny.mvc.helpers.IFrameHandler;
	import com.puny.mvc.models.Model;
	import com.puny.utils.easing.OneEndsTrigonometricEasing;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.geom.Matrix;
	import flash.geom.Rectangle;
	
	public class Distributor extends Object implements IFrameHandler
	{
		public static const EXHALE:int = 1;
		public static const INHALE:int = -1;
		private var _models:Array = new Array();
		private var _frame:Number;
		private var _obj:DisplayObject;
		private var _type:int;
		private var _halfWidth:Number;
		private var _halfHeight:Number;
		private var _gaussian:IGaussian;
		/**
		 * This class must be extended. An extended class can set <code>getInternalClass()</code> in the first argument to instanciate. 
		 * 
		 * @param dummy internnal class to prevent instanciating Distributor class itself.
		 * @param obj
		 * @param type
		 * @param frame
		 * @param size
		 * @param bg
		 * 
		 */
		public function Distributor(dummy:Dummy, obj:DisplayObject, type:int, frame:int, size:int=1, bg:uint=0xFFFFFF) {
			var rect:Rectangle = obj.getBounds(obj.parent);
			var local:Rectangle = obj.getBounds(obj); 
			var matrix:Matrix = new Matrix(1,0,0,1,-local.x,-local.y);

			var data:BitmapData = new BitmapData(local.width,local.height,true,bg);
			data.draw(obj,matrix);
			
			_frame = frame;
			_obj = obj;
			_type = type;

			_halfWidth = int(rect.width / 2) + rect.x;
			_halfHeight = int(rect.height / 2) + rect.y;

			var x:int;
			var y:int;
			var pixel:BitmapData;
			for(y = 0;y < rect.height;y+=size) {
				for(x = 0;x < rect.width;x+=size) {
					pixel = new BitmapData(size,size,true,bg);
					pixel.draw(data,new Matrix(1,0,0,1,-x,-y));
					if (!isEmpty(pixel,bg)) {
						_models.push(getModel(x,y,rect,new Bitmap(pixel)));
					}
				}
			}
			trace("Broken into",_models.length,"pieces.");
		}
		
		protected function get frame():int {
			return int(Random.between(.5*_frame,_frame));
		}
		
		protected function get type():int {
			return _type;
		}
		
		protected function get halfWidth():Number {
			return _halfWidth;
		}
		
		protected function get halfHeight():Number {
			return _halfHeight;
		}
		
		protected function getModel(x:int,y:int,rect:Rectangle,bmp:Bitmap):Model {
			var model:Model = new Model();
			model.bitmap = bmp;
			model.bitmap.x = rect.x+x;
			model.bitmap.y = rect.y+y;
			model.easingX = new OneEndsTrigonometricEasing(model.bitmap.x, model.bitmap.x, frame,-1);
			model.easingY = new OneEndsTrigonometricEasing(model.bitmap.y, model.bitmap.y, frame,-1);
			return model;
		}		
				
		public function before():void {
			for each(var model:Model in _models) {
				_obj.parent.addChild(model.bitmap);
			}
			_obj.visible = false;
		}
		
		private function isEmpty(data:BitmapData,bg:uint):Boolean {
			var c:uint;
			for(var y:int = 0;y < data.height;y++) {
				for(var x:int = 0;x < data.width;x++) {
					c = data.getPixel(x,y);
					if (c != bg) {
						return false;
					}
				}
			}
			return true;
		} 
		
		public function loop():Boolean {
			for each(var model:Model in _models) {
				model.bitmap.x = model.easingX.forward();
				model.bitmap.y = model.easingY.forward();
				uniqueAction(model);
			}
			_frame--;
			return _frame > 0;
		}
		
		public function after():void {
			var model:Model;
			if (_type == INHALE) {
				_obj.visible = true;
			}
			while(_models.length > 0) {
				model = _models.pop();
				if (_obj.parent != null) {
					_obj.parent.removeChild(model.bitmap);
				}
				model.bitmap = null;
			}
		}
		
		protected function uniqueAction(model:Model):void {
			
		}
		
		protected function getInternalClass():Dummy	{
			return new Dummy();
		}	
	}
	
}

internal class Dummy {
}